package com.marquisx.tzdice.database;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

import com.marquisx.tzdice.model.DiceAction;

public class DiceActionDBAdapter
{
	private static final String TAG = "TZDice:TZDiceDBAdapter";
	private static final String DATABASE_NAME = "tzdice.db";
	private static final String DATABASE_TABLE = "actiontable";
	private static final int DATABASE_VERSION = 1;
	
	public static final String KEY_ID = "_id";
	public static final int KEY_COLUMN = 0;
	
	public static final String KEY_NAME = "name";
	public static final int NAME_COLUMN = 1;
	
	public static final String KEY_DESCRIPTION = "discription";
	public static final int DESCRIPTION_COLUMN = 2;
	
	public static final String KEY_PICTUREID = "pictureid";
	public static final int PICTUREID_COLUMN = 3;
	
	public static final String KEY_DICE = "dice";
	public static final int DICE_COLUMN = 4;
	
	public static final String KEY_TIMES = "times";
	public static final int TIMES_COLUMN = 5;
	
	public static final String KEY_OFFSET = "offset";
	public static final int OFFSET_COLUMN = 6;
	
	public static final String KEY_HASTHRESHOLD = "hasthreshold";
	public static final int HASTHRESHOLD_COLUMN = 7;
	
	public static final String KEY_THRESHOLD = "THRESHOLD";
	public static final int THRESHOLD_COLUMN = 8;
	
	public static final String[] ALL_COLUMNS = new String[]{
		KEY_ID,
		KEY_NAME, KEY_DESCRIPTION, KEY_PICTUREID, KEY_DICE,
		KEY_TIMES, KEY_OFFSET, KEY_HASTHRESHOLD, KEY_THRESHOLD
	};
	
	// SQL statement to create a new database.
	private static final String DATABASE_CREATE = "create table " +
		DATABASE_TABLE + " (" + 
		KEY_ID + " integer primary key autoincrement, " +
		KEY_NAME + " text not null, " +
		KEY_DESCRIPTION + " text, " +
		KEY_PICTUREID + " interger, " +
		KEY_DICE + " interger nut null, " +
		KEY_TIMES + " integer nut null, " +
		KEY_OFFSET + " integer nut null, " +
		KEY_HASTHRESHOLD + " integer, " +
		KEY_THRESHOLD + " integer" +		
		");";
	
	// Variable to hold the database instance
	private SQLiteDatabase db;
	// Context of the application using the database.
	private final Context context;
	// Database open/upgrade helper
	private DBHelper dbHelper;
	
	public DiceActionDBAdapter(Context context)
	{
		this.context = context;
		dbHelper = new DBHelper(this.context, DATABASE_NAME, null, DATABASE_VERSION);
	}
	
	public DiceActionDBAdapter open() throws SQLException
	{
		try
		{
			db = dbHelper.getWritableDatabase();
		}
		catch (SQLiteException ex)
		{
			Log.e(TAG, ex.getMessage());
			db = dbHelper.getReadableDatabase();
		}
		return this;
	}
	
	public void close()
	{
		if( db != null )
		{
			db.close();
		}
	}
	
	public long insertEntry(DiceAction diceAction)
	{
		assert( diceAction != null );
		
		//Create a new row of values to insert.
		ContentValues newValues = convertDiceActionToContentValue(diceAction);
		
		long newId = db.insert(DATABASE_TABLE, null, newValues);
		diceAction.setId(newId);
		
		return newId;	//index
	}
	
	public void insertEntries(List<DiceAction> diceActionList)
	{
		assert (diceActionList != null && diceActionList.size() !=0);
		
		for( DiceAction diceAction : diceActionList)
		{
			insertEntry(diceAction);
		}
		
	}
	
	public boolean deleteAll()
	{
		return db.delete(DATABASE_TABLE, null, null) > 0;
	}
	
	public boolean removeEntry(DiceAction diceAction)
	{
		return removeEntry(diceAction.getId());
	}
	
	public boolean removeEntry(long rowIndex)
	{
		return db.delete(DATABASE_TABLE, KEY_ID  + "=" + rowIndex, null) > 0;
	}
	
	public DiceAction getEntry(long rowIndex)
	{
		Cursor cursor = db.query(true, DATABASE_TABLE, 
				ALL_COLUMNS, KEY_ID + "=" + rowIndex, 
				null, null, null, null, null);
		
		if( cursor.getCount() == 0 || !cursor.moveToFirst() )
		{
			//throw new SQLException("No dice action found for row: " + rowIndex);
			return null;
		}
		
		DiceAction result = convertRecordToDiceAction(cursor);
		
		return result;
	}
	
	public boolean updateEntry(DiceAction diceAction)
	{
		assert (diceAction.getId() > 0 );
		
		return updateEntry(diceAction.getId(), diceAction);
	}
	
	public boolean updateEntry(long rowIndex, DiceAction diceAction)
	{
		//Create a new row of values to insert.
		ContentValues newValues = convertDiceActionToContentValue(diceAction);
		
		String where = KEY_ID + "=" + rowIndex;
		
		return db.update(DATABASE_TABLE, newValues, where, null) > 0;
	}
	
	public List<DiceAction> getAllEntries()
	{
		Cursor cursor = getAllDiceActionCursor();
		
		List<DiceAction> resultList = new ArrayList<DiceAction>();
		
		if( cursor.getCount() == 0 || !cursor.moveToFirst() )
		{
			Log.w(TAG, "No dice action found in table");
			return resultList;
		}
		
		do
		{
			resultList.add(convertRecordToDiceAction(cursor));
		}
		while(cursor.moveToNext());

		return resultList;
	}
	
	public Cursor getAllDiceActionCursor()
	{
		return db.query(DATABASE_TABLE, ALL_COLUMNS, null, null, null, null, null);
	}
	
	private DiceAction convertRecordToDiceAction(Cursor cursor)
	{
		DiceAction diceAction = new DiceAction();
		
		diceAction.setId(cursor.getLong(KEY_COLUMN));
		diceAction.setName(cursor.getString(NAME_COLUMN));
		diceAction.setDescription(cursor.getString(DESCRIPTION_COLUMN));
		diceAction.setPictureId(cursor.getInt(PICTUREID_COLUMN));
		diceAction.setDice(cursor.getInt(DICE_COLUMN));
		diceAction.setTimes(cursor.getInt(TIMES_COLUMN));
		diceAction.setOffset(cursor.getInt(OFFSET_COLUMN));
		diceAction.setHasThreshold(cursor.getInt(HASTHRESHOLD_COLUMN) == 1 ? true: false);
		diceAction.setThreshold(cursor.getInt(THRESHOLD_COLUMN));
		
		return diceAction;
	}
	
	private ContentValues convertDiceActionToContentValue (DiceAction diceAction)
	{
		//Create a new row of values to insert.
		ContentValues values = new ContentValues();
		//Assign values for each row.
		values.put(KEY_NAME, diceAction.getName());
		values.put(KEY_DESCRIPTION, diceAction.getDescription());
		values.put(KEY_PICTUREID, diceAction.getPictureId());
		values.put(KEY_DICE, diceAction.getDice());
		values.put(KEY_TIMES, diceAction.getTimes());
		values.put(KEY_OFFSET, diceAction.getOffset());
		values.put(KEY_HASTHRESHOLD, diceAction.isHasThreshold()?"1":"0");
		values.put(KEY_THRESHOLD, diceAction.getThreshold());
		
		return values;
	}
	

	
	private static class DBHelper extends SQLiteOpenHelper
	{
		private static final String TAG = "TZDice: DBHelper";
		public DBHelper(Context context, String name, CursorFactory factory, int version)
		{
			super(context, name, factory, version);
		}

		@Override
		public void onCreate(SQLiteDatabase db)
		{
			Log.i(TAG, "create db using SQL: " + DATABASE_CREATE);
			db.execSQL(DATABASE_CREATE);
		}

		// Called when there is a database version mismatch meaning that the version 
		// of the database on disk needs to be upgraded to the current version.
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
		{
			// Log the version upgrade
			Log.w(TAG, "Upgrading from version " + 
						oldVersion + " to " + 
						newVersion + ", which will destroy all old data");
			
			// Upgrade the existing database to conform to the new version. Multiple
			// previous versions can be handled by comparing oldVersion and newVersion
			// values.
			
			// The simplest case is to drop the old table and create a new one.
			db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
			// Create a new one.
			onCreate(db);
		}
	}

}
